package com.gopay.checkorder.service.task;

import com.gopay.common.Result;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BcdlMessage;
import com.gopay.common.domain.bank.boc.bcdl.queryTrans.res.B2e0035Res;
import com.gopay.common.domain.bank.boc.bcdl.queryTrans.res.B2e0035StatusRes;
import com.gopay.common.domain.bank.boc.bcdl.queryTrans.res.TransResQueryB2e0035Body;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.SendMail;
import com.gopay.remote.bank.BcdlInteractRemoteService;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import java.io.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 中国银行对账文件下载
 *
 * @author ssj
 * @date 2017-09-10
 */
public class BocDownloadTaskImpl implements Task {
    private final static Logger logger = LoggerFactory.getLogger("BocDownloadTaskImpl");

    @Resource(name = "bankBcdlClient")
    private BcdlInteractRemoteService bankBcdlClient;

    private String bank;

    @Resource(name = "ipayDayEndConfig")
    private Map<String, String> ipayDayEndConfig;

    @Override
    public void doTask() {
        String  configPath="/usr/local/ciecc/bankFiles/BOC/"+ GetDate()+"/";
        Result result = null;
        String fileNameExcel = "";
        try {

            StopWatch sw = new StopWatch();
            sw.start();

            if ("off".equals(ipayDayEndConfig.get("mailSwitch"))) {
                logger.error("BocDownloadTaskImpl: 不进行ftp操作直接返回!");
                return;
            }

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd HH:mm");
            List<B2e0035Res> orderList = new ArrayList<B2e0035Res>();
            BcdlMessage base = new BcdlMessage();
            String DateStr1 = getCurrDate();
            String DateStr2 = GetDate() + " 03:30";
            String DateStr3 = GetDate() + " 10:30";
            Date dateTime1 = dateFormat.parse(DateStr1);
            Date dateTime2 = dateFormat.parse(DateStr2);
            Date dateTime3 = dateFormat.parse(DateStr3);
            String startDate = "";
            String endDate = "";
            String dateType = "";
            //每天凌晨3点半执行一次,获取前一天的中国银行对账信息
            if (dateTime1.getTime() == dateTime2.getTime()) {
                // 前一天日期
                startDate = DateUtils.getYesterday();
                dateType = "0330";
                base.setOrderDate(startDate);
                // 查询类型非空数码  4 位非空枚举：2001（当日查询）2002（历史 查询） 2005 （T+1查询 T日夜间批量交易
                base.setTradeType(2002);
                logger.info("BocDownloadTaskImpl 上午03:30 开始执行中国银行对账明细信息当,日期为:" + startDate);
            } else if (dateTime1.getTime() == dateTime3.getTime()) {//上午10:30 开始执行中国银行对账明细信息当
                //开始日期
                logger.info("BocDownloadTaskImpl 上午10:30 开始执行中国银行对账明细信息当,日期为:" + startDate);
                dateType = "1030";
                base.setOrderDate(GetDate());
                // 查询类型非空数码  4 位非空枚举：2001（当日查询）2002（历史 查询） 2005 （T+1查询 T日夜间批量交易
                base.setTradeType(2001);
            } else {
                //开始日期  下午三点半开始执行一次
                startDate = GetDate();
                base.setOrderDate(startDate);
                dateType = "1530";
                // 查询类型非空数码  4 位非空枚举：2001（当日查询）2002（历史 查询） 2005 （T+1查询 T日夜间批量交易
                base.setTradeType(2001);
                logger.info(" BocDownloadTaskImpl 上午15:30 开始执行中国银行对账明细信息当,日期为:" + startDate);
            }
            fileNameExcel = "BOC_DCBL_" + GetDate() + "_" + getGregorianCalendar() + "_" + dateType + ".xls";
            base.setBank("BOC");
            base.setDcblType(1);
            logger.info("开始执行中国银行对账明细job----------------------------");
            result = bankBcdlClient.queryAcctDetail(base);
            TransResQueryB2e0035Body body = (TransResQueryB2e0035Body) result.getDefaultModel();
            B2e0035StatusRes status = body.getTrans().getTrbB2e0035Res().getB2e0035Status();
            String rspcod = status.getRspcod();
            String rspmsg = status.getRspmsg();
            if ("B001".equals(rspcod)) {
                logger.info("中国银行对账明细结束job =" + rspcod + "     rspmsg=" + rspmsg);
                return;
            } else {
                List<B2e0035Res> list = body.getTrans().getTrbB2e0035Res().getB2e0035Res();
                int count = body.getTrans().getTrbB2e0035Res().getB2e0035Res().size();
                //总页数
                int NotenumSize = Integer.valueOf(body.getTrans().getTrbB2e0035Res().getNotenum());
                //每页条数
                int Totalnum = Integer.valueOf(body.getTrans().getTrbB2e0035Res().getTotalnum());
                //循环次数
                int size = NotenumSize / (Totalnum) + ((NotenumSize % Totalnum == 0) ? 0 : 1);
                for (int i = 1; i <= size; i++) {
                    if (i == 1) {
                        base.setDcblType(i);
                    } else {
                        base.setDcblType(50 * (i - 1) + 1);
                    }
                    result = bankBcdlClient.queryAcctDetail(base);
                    TransResQueryB2e0035Body returnbody = (TransResQueryB2e0035Body) result.getDefaultModel();
                    B2e0035StatusRes restatus = returnbody.getTrans().getTrbB2e0035Res().getB2e0035Status();
                    String rrspcod = restatus.getRspcod();
                    String rrspmsg = restatus.getRspmsg();
                    List<B2e0035Res> returnbodylist = returnbody.getTrans().getTrbB2e0035Res().getB2e0035Res();
                    if (returnbodylist.size() > 0)
                        orderList.addAll(returnbodylist);
                    if ("B001".equals(rrspcod)) {
                        logger.info("中国银行对账明细结束job  B001 rrspcod  =" + rrspcod + "     rspmsg=" + rrspmsg);
                        break;
                    } else if ("B002".equals(rrspcod)) { //成功未完
                        logger.info("中国银行对账明细结束job B002 job =" + rrspcod + "     rspmsg=" + rrspmsg);
                    } else if ("B003".equals(rrspcod)) {
                        logger.info("中国银行对账明细结束job B003 job =" + rrspcod + "     rrspmsg=" + rrspmsg);
                        break;
                    } else {
                        if (ProcCodeConstants.PROC_CODE_100S1000.equals(result.getResultCode())) {
                            logger.info("中国银行对账明细结束job  ResultCode =" + result.getResultCode() + "   ErrorMsg=" + result.getErrorMsg());
                        } else {
                            logger.info("中国银行对账明细结束job  ResultCode =" + result.getResultCode() + "   ErrorMsg=" + result.getErrorMsg());
                        }
                    }
                }
                logger.info("总条数 =" + NotenumSize + "  分页=" + Totalnum + "  循环次数size=" + size + "   执行完的总条数=" + orderList.size());
                logger.info("BocDownloadTaskImpl  开始组装Excel数据job");
                exportFeedBack(orderList, configPath, fileNameExcel);
                logger.info("BocDownloadTaskImpl  结束组装Excel完成");
                //发送邮件
                sendMessage(fileNameExcel, configPath);
                //清除缓存
                orderList.clear();

            }
            sw.stop();

        } catch (Exception e) {
            logger.error("BcdlOrderCheckDccTaskImpl  异常");
            e.printStackTrace();
        }
    }

    /**
     * 发送邮件
     * @param fileNameExcel
     * @param excel_Path
     */
    public void sendMessage(String fileNameExcel, String excel_Path) {
        try {
            List sendFile = new ArrayList();
            List names = new ArrayList();
            String[] cc = ipayDayEndConfig.get("sendmail.cc").split(","); // 获取多个抄送人
            List<String> ccList = Arrays.asList(cc);
            names.add(fileNameExcel);
            //附件标题
            String subject = "中国银行对账文件明细下载";

            logger.info("BocDownloadTaskImpl  fileNameExcel 路径:" + fileNameExcel + "excel_Path路径:" + excel_Path);
            // 附件内容
            String messageText = DateUtils.format(new Date(), "yyyy-MM-dd HH:mm") + ": 中国银行对账文件请您见附件查收!" + fileNameExcel;
            for (int i = 0; i < names.size(); i++) {
                sendFile.add(excel_Path + (String) names.get(i));
            }
            logger.error("sendMessage config:--host:"
                    + ipayDayEndConfig.get("sendmail.host") + "----sender:"
                    + ipayDayEndConfig.get("sendmail.sender") + "----username:"
                    + ipayDayEndConfig.get("sendmail.username")
                    + "----password:"
                    + ipayDayEndConfig.get("sendmail.password")
                    + "----receiver:"
                    + ipayDayEndConfig.get("sendmail.receiver")
                    +"cc="+ipayDayEndConfig.get("sendmail.cc"));
            // 发送邮件
            SendMail.sendMessage(ipayDayEndConfig.get("sendmail.host"),
                    ipayDayEndConfig.get("sendmail.sender"),
                    ipayDayEndConfig.get("sendmail.username"),
                    ipayDayEndConfig.get("sendmail.password"),
                    ipayDayEndConfig.get("sendmail.receiver"), subject,
                    messageText, "text/html;charset=gb2312", ccList, sendFile,
                    names);
            logger.info("BocDownloadTaskImpl  中国银行对账明细邮件发送成功!");
        } catch (MessagingException e) {
            logger.error("BocDownloadTaskImpl 中国银行对账文件明细发送邮件失败!", e);
            e.printStackTrace();
            ;

        }

    }

    /**
     * Excel报文组装
     * @param orderlist
     * @param excexPath
     * @param fileNameExcel
     */
    public void exportFeedBack(List<B2e0035Res> orderlist, String excexPath, String fileNameExcel) {
        //文件名称
        String fileName = fileNameExcel;
        String[] title = new String[]{"交易类型", "业务类型", "付款人开户行号", "付款人开户行名", "付款人账号", "付款人名称", "收款人开户行行号", "收款人开户行名", "收款人账号", "收款人名称",
                "交易日期", "交易时间", "交易货币", "交易金额", "交易后余额", "起息日期", "汇率", "交易流水号", "客户申请号", "客户业务编号",
                "凭证类型", "凭证号码", "记录标识号", "摘要", "用途", "交易附言", "备注"};
        int j = 0;
        int size = orderlist.size();
        //备付金账号
        String actacn = "";
        int Ibknum = 0;
        int IbkSize = 0;
        double IbkSizeAmt = 0;
        double IbknumAmt = 0;
        String[][] values = new String[size][];
        for (int k = 0; k < orderlist.size(); k++) {
            //将对象内容转换成string
            B2e0035Res res = orderlist.get(k);
            actacn = res.getFractn().getActacn();
            String interinfo = res.getInterinfo();
            String[] obj = interinfo.split("//");
            String str0 = obj[0].toString();
            String str1 = obj[1].toString();
            String str2 = obj[2].toString();
            String str3 = obj[3].toString();
            values[j] = new String[title.length];
            //交易类型  来往账标识1-来账，2-  往账）
            values[j][0] = res.getDirection() == "1" ? "来账" : "往账";
            //业务类型
            values[j][1] = getMap(res.getBustype());
            //付款人开户行号
            values[j][2] = res.getFractn().getIbknum();
            if (res.getFractn().getIbknum().equals("02275") && !res.getBustype().equals("7601")) {
                Ibknum++;//7601	B2B支付
                //构造以字符串内容为值的BigDecimal类型的变量bd
                BigDecimal bd = new BigDecimal(res.getTxnamt());
                //设置小数位数，第一个变量是小数位数，第二个变量是取舍方法(四舍五入)
                bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
                //转化为字符串输出
                IbknumAmt += bd.doubleValue();
            } else {
                IbkSize++;
                //构造以字符串内容为值的BigDecimal类型的变量bd
                BigDecimal bd = new BigDecimal(res.getTxnamt());
                //设置小数位数，第一个变量是小数位数，第二个变量是取舍方法(四舍五入)
                bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
                //转化为字符串输出
                IbkSizeAmt += bd.doubleValue();
            }
            //付款人开户行名
            values[j][3] = res.getFractn().getIbkname();
            //付款人账号
            values[j][4] = res.getFractn().getActacn();
            //付款人名称
            values[j][5] = res.getFractn().getAcntname();
            //收款人开户行行号
            values[j][6] = "";
            //收款人开户行名
            values[j][7] = res.getToactnRes().getTobank();
            //收款人账号
            values[j][8] = res.getToactnRes().getActacn();
            //收款人名称
            values[j][9] = res.getToactnRes().getToname();
            //交易日期
            values[j][10] = res.getTxndate();
            //交易时间
            SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
            //交易时间 TimeStab
            values[j][11] = format.format(com.gopay.common.util.DateUtils.strToDate(res.getTxndate() + res.getTxntime()));
            //交易货币
            values[j][12] = res.getTrncur();
            //交易金额
            values[j][13] = res.getTxnamt();
            //交易后余额
            values[j][14] = res.getAcctbal();
            //起息日期
            values[j][15] = res.getValdat();
            //汇率
            values[j][16] = res.getFxrate();
            //交易流水号
            values[j][17] = res.getVchnum();
            //客户申请号
            values[j][18] = str1.toString().substring(6, 18);
            //客户业务编号
            values[j][19] = res.getInsid();
            //凭证类型
            values[j][20] = res.getVouchtp();
            //凭证号码
            values[j][21] = res.getVouchnum();
            //记录标识号
            values[j][22] = res.getTransid();
            //摘要
            values[j][23] = String.valueOf(str1.replace(str1.substring(0, 2), ""));
            //用途
            values[j][24] = String.valueOf(str2.replace(str2.substring(0, 2), ""));
            //交易附言
            values[j][25] = String.valueOf(str0.replace(str0.substring(0, 2), ""));
            //备注
            values[j][26] = String.valueOf(str3.replace(str3.substring(0, 2), ""));
            j++;
        }
        String[] titlehead = new String[]{"查询账号[ Inquirer account number ]", "总笔数[Total number ]", "借方发生总笔数[ Total Numbers of Debited Payments ]",
                "借方发生总额[ Total Debit Amount of Payments ]", "贷方发生总笔数[ Total Numbers of Credited Payments ]", "贷方发生总额[ Total Credit Amount of Payments ]", "查询时间范围[ Time Range ]"};
        int jHead = 0;
        int sizeHead = 1;
        String[] valuesHead = new String[]{actacn, String.valueOf(orderlist.size()),
                String.valueOf(Ibknum), String.valueOf(new BigDecimal(IbknumAmt).setScale(2, BigDecimal.ROUND_HALF_UP)),
                String.valueOf(IbkSize), String.valueOf(IbkSizeAmt), ""};
        HSSFWorkbook wb = getHSSFWorkbook(fileName, titlehead, valuesHead, title, values, null);
        //将文件存到指定位置
        try {
            File filemk = new File(excexPath);
            //创建目录
            if (!filemk.exists()) filemk.mkdirs();
            File file = new File(excexPath + fileName);
            OutputStream out = new FileOutputStream(file, true);
            wb.write(out);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public HSSFWorkbook getHSSFWorkbook(String sheetName, String[] titleHead, String[] valuesHead, String[] title, String[][] values, HSSFWorkbook wb) {
        // 第一步，创建一个webbook，对应一个Excel文件
        if (wb == null) wb = new HSSFWorkbook();
        // 第二步，在webbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);
        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short
        HSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(HSSFCellStyle.ALIGN_LEFT); // 创建一个居中格式
        //设置Excel标题宽度
        sheet.setColumnWidth(0, 35 * 256);
        // 在索引0的位置创建单元格（左上端）
        HSSFCell cell = row.createCell(0);
        // 定义单元格为字符串类型
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);

        CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 0,
                11);
//
        for (int i = 0; i < titleHead.length; i++) {
            row = sheet.createRow(i);
            row.createCell(0).setCellValue(titleHead[i]);
            cellRangeAddress = new CellRangeAddress(3, 3, 2, 11);
            sheet.addMergedRegion(cellRangeAddress);
            row.createCell(1).setCellValue(valuesHead[i].toString());
        }
        //创建标题
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
        }
//        创建内容
        for (int i = 0; i < values.length; i++) {
            row = sheet.createRow(i + 7);
            for (int j = 0; j < values[i].length; j++)
                row.createCell(j).setCellValue(values[i][j]);
        }
        return wb;
    }

    public static String getMap(String key) {
        Map<String, String> map = new HashMap<>();
        map.put("7501", "资金归集");
        map.put("7502", "资金下拨");
        map.put("7503", "现金管理收费");
        map.put("2401", "国债买入");
        map.put("2402", "国债卖出");
        map.put("2403", "国债还本付息");
        map.put("2404", "国债收费");
        map.put("2405", "国债调账");
        map.put("2301", "基金认购");
        map.put("2302", "基金申购");
        map.put("2303", "基金失败退款");
        map.put("2304", "基金赎回");
        map.put("2305", "基金现金分红");
        map.put("2306", "基金撤单");
        map.put("2307", "基金调账");
        map.put("3701", "国际结算");
        map.put("7401", "电子银承汇票");
        map.put("7402", "电子商承汇票");
        map.put("7403", "纸质银承汇票");
        map.put("7404", "纸质商承汇票");
        map.put("7405", "保证金转出");
        map.put("7406", "保证金预存");
        map.put("7407", "咨询服务费");
        map.put("6101", "境内外币");
        map.put("6102", "代理业务");
        map.put("6201", "境内外币结算");
        map.put("7001", "净额清算");
        map.put("8101", "网上支付");
        map.put("8102", "第三方支付");
        map.put("8103", "大额支付");
        map.put("8104", "小额普通支付");
        map.put("8105", "小额定期支付");
        map.put("8106", "小额实时支付");
        map.put("4101", "报关预扣");
        map.put("4102", "报关预扣退款");
        map.put("4103", "报关核单");
        map.put("4104", "隔日退款");
        map.put("4105", "电子商务");
        map.put("5201", "B股转账");
        map.put("5202", "代收付");
        map.put("5101", "信用卡还款");
        map.put("5102", "实时代收");
        map.put("5104", "个人小额结汇");
        map.put("5105", "个人小额售汇");
        map.put("7601", "B2B支付");
        map.put("7602", "B2B实付");
        map.put("7603", "B2B返款");
        map.put("7604", "B2B退货");
        map.put("5111", "代发扣款");
        map.put("5112", "代发失败退款");
        map.put("5113", "代收入账");
        map.put("6001", "中央财政支付");
        map.put("6002", "中央财政退回");
        map.put("6003", "专户资金上划");
        map.put("6004", "上划异常冲正");
        map.put("4801", "国库实时缴税");
        map.put("4802", "国库批量缴税");
        map.put("4803", "国库柜台缴税");
        map.put("6401", "银期转账");
        map.put("6402", "出入金");
        map.put("4900", "银证转帐");
        map.put("4902", "银商转帐");
        map.put("0001", "国内汇款");
        map.put("0002", "国外汇款");
        map.put("0003", "人行大额");
        map.put("0004", "人行小额");
        map.put("0005", "现金存款");
        map.put("0006", "转帐收入");
        map.put("0007", "汇票");
        map.put("0008", "本票");
        map.put("0009", "支票圈存");
        map.put("0010", "冲账");
        map.put("0011", "冲正");
        map.put("0012", "承兑汇票");
        map.put("0013", "委托托收");
        map.put("0014", "保证金");
        map.put("0015", "现金取款");
        map.put("0016", "转帐支出");
        map.put("0017", "贷款放款");
        map.put("0018", "贷款还款");
        map.put("0019", "转账");
        map.put("0020", "光票业务");
        map.put("0021", "实时汇划");
        map.put("0022", "退汇");
        map.put("0023", "自动归集");
        map.put("0024", "自动下拨");
        map.put("0029", "预收息");
        map.put("0030", "结利息税");
        map.put("0031", "结息");
        map.put("0032", "批量收费");
        map.put("0041", "收费");
        map.put("0098", "尾记录");
        map.put("0099", "其他");
        map.put("0051", "ATM存款");
        map.put("0052", "ATM取款");
        map.put("0053", "ATM转帐");
        map.put("0054", "POS转帐");
        map.put("0055", "POS消费");
        map.put("0056", "POS消费撤销");
        map.put("0057", "POS退货");
        map.put("0058", "利息调整");
        map.put("0059", "费用垫款销账");
        map.put("0060", "费用垫款挂账");
        map.put("0061", "暂付款挂账");
        map.put("0062", "暂付款销账");
        map.put("0063", "账户结清");
        map.put("0064", "本金调整");
        map.put("0065", "拖欠金额调整");
        map.put("0066", "贷款结本息");
        map.put("0069", "同城交换");
        map.put("0070", "国际汇出汇款");
        map.put("0071", "国际汇入汇款");
        map.put("0072", "国际汇出汇票");
        map.put("0073", "国际汇入汇票");
        map.put("7504", "多向补平");
        map.put("7505", "多向还原");
        map.put("7506", "利息派发");
        map.put("8321", "批量付款");
        map.put("8400", "理财认购");
        map.put("8401", "理财申购");
        map.put("8402", "理财赎回");
        map.put("8404", "理财红利");
        map.put("8406", "理财本金");
        map.put("6601", "提出业务");
        map.put("6602", "提入业务");
        map.put("5901", "电银收费");
        map.put("5902", "短信收费");
        map.put("7519", "外债利息");
        map.put("7520", "放款利息");
        map.put("7521", "汇出交易");
        map.put("7522", "汇入交易");
        map.put("7523", "分户调整");
        map.put("7524", "委贷放款");
        map.put("7525", "委贷还款");
        map.put("7526", "借贷放款");
        map.put("7527", "借贷还款");
        map.put("7528", "借贷利息");
        map.put("1101", "还信用卡");
        map.put("AI11", "商户收单");
        map.put("8311", "代发划转");
        map.put("8312", "代发退划");
        return map.get(key);

    }

    /**
     * 返回系统当前日期
     *
     * @return
     */
    public static String GetDate() {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        String date = format.format(new Date());
        return date;
    }

    public void setBank(String bank) {
        this.bank = bank;
    }

    public String getBank() {
        return bank;
    }

    /**
     * 上午 下午转换
     *
     * @return
     */
    public String getGregorianCalendar() {
        GregorianCalendar ca = new GregorianCalendar();
        //结果为“0”是上午 结果为“1”是下午
        String AM_PM = "";
        if (ca.get(GregorianCalendar.AM_PM) == 0) AM_PM = "AM";
        else AM_PM = "PM";
        return AM_PM;
    }

    /**
     * 获取当前时间
     *
     * @param pattern 格式
     * @return
     */
    public static String getCurrDate(String pattern) {
        long d = System.currentTimeMillis();
        Date date = new Date(d);
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * 获取当前时间(格式:yyyyMMddHHmm)
     *
     * @return
     */
    public static String getCurrDate() {
        return getCurrDate("yyyyMMdd HH:mm");
    }


}
